﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LotteryVote.Entity;
using LotteryVote.Data;
using LotteryVote.Utility;
using LotteryVote.Logic.Exceptions;

namespace LotteryVote.Logic
{
    public class UserCommissionFacade
    {
        #region
        private CommissionValueDataAccess _daCommValue;
        internal CommissionValueDataAccess DaCommValue
        {
            get
            {
                if (_daCommValue == null)
                    _daCommValue = new CommissionValueDataAccess();
                return _daCommValue;
            }
            set
            {
                _daCommValue = value;
            }
        }

        private UserCommissionDataAccess _daUserComm;
        internal UserCommissionDataAccess DaUserComm
        {
            get
            {
                if (_daUserComm == null)
                    _daUserComm = new UserCommissionDataAccess();
                return _daUserComm;
            }
            set
            {
                _daUserComm = value;
            }
        }

        private CompanyTypeDataAccess _daCompanyType;
        internal CompanyTypeDataAccess DaCompanyType
        {
            get
            {
                if (_daCompanyType == null)
                    _daCompanyType = new CompanyTypeDataAccess();
                return _daCompanyType;
            }
            set
            {
                _daCompanyType = value;
            }
        }

        private GameTypeDataAccess _daGameType;
        internal GameTypeDataAccess DaGameType
        {
            get
            {
                if (_daGameType == null)
                    _daGameType = new GameTypeDataAccess();
                return _daGameType;
            }
            set
            {
                _daGameType = value;
            }
        }

        private UserFacade _userFacade;
        public UserFacade UserFacade
        {
            get
            {
                if (_userFacade == null)
                    _userFacade = new UserFacade();
                return _userFacade;
            }
            set
            {
                _userFacade = value;
            }
        }

        private CommisionGroupFacade _commGroupFacade;
        public CommisionGroupFacade CommGroupFacade
        {
            get
            {
                if (_commGroupFacade == null)
                    _commGroupFacade = new CommisionGroupFacade();
                return _commGroupFacade;
            }
            set
            {
                _commGroupFacade = value;
            }
        }

        private MemberPackageDataAccess _daMemberPack;
        internal MemberPackageDataAccess DaMemberPack
        {
            get
            {
                if (_daMemberPack == null)
                    _daMemberPack = new MemberPackageDataAccess();
                return _daMemberPack;
            }
            set
            {
                _daMemberPack = value;
            }
        }
        #endregion

        public void AddDefaultUserCommission(User user, int[] species)
        {
            foreach (var specieId in species)
                AddDefaultUserCommission(user, specieId);
        }
        public void AddDefaultUserCommission(User user, int specieId)
        {
            List<CommissionValue> commValueList = new List<CommissionValue>();
            DaCommValue.ExecuteWithTransaction(() =>
            {
                DaCompanyType.Tandem(DaCommValue);
                DaGameType.Tandem(DaCommValue);
                var companyTypes = DaCompanyType.GetAllCompanyType();
                var gameTypes = DaGameType.GetAllGameType();
                foreach (var companyType in companyTypes)
                {
                    foreach (var gameType in gameTypes)
                    {
                        commValueList.Add(new CommissionValue
                        {
                            CompanyType = companyType,
                            GameType = gameType
                        });
                    }
                }
                this.AddUserCommission(user, specieId, commValueList);
            });
        }
        public void AddUserCommission(User user, int specieId, IList<CommissionValue> commValueList)
        {
            DaUserComm.ExecuteWithTransaction(() =>
            {
                UserCommission userComm = new UserCommission
                {
                    SpecieId = specieId,
                    UserId = user.UserId
                };
                DaUserComm.InsertUserCommission(userComm);

                DaCommValue.Tandem(DaUserComm);
                foreach (var commValue in commValueList)
                {
                    commValue.CommissionId = userComm.CommissionId;
                    DaCommValue.InsertCommission(commValue);
                }
            });
        }
        public void UpdateUserCommission(IList<CommissionValueItem> commValueItemList)
        {
            List<CommissionValue> commssionValueList = new List<CommissionValue>();
            IDictionary<int, GameType> dicGameType = new Dictionary<int, GameType>();
            IDictionary<int, CompanyTypeModel> dicCompanyType = new Dictionary<int, CompanyTypeModel>();
            int commissionId = commValueItemList[0].CommissionId;
            foreach (var item in commValueItemList)
            {
                if (!dicCompanyType.ContainsKey(item.CompanyTypeId))
                {
                    var comType = DaCompanyType.GetCompanyType(item.CompanyTypeId);
                    dicCompanyType.Add(item.CompanyTypeId, comType);
                }
                if (!dicGameType.ContainsKey(item.GameId))
                {
                    var gameType = DaGameType.GetGameType(item.GameId);
                    dicGameType.Add(item.GameId, gameType);
                }
                if (item.Comm < 0)
                    item.Comm = Math.Abs(item.Comm);
                commssionValueList.Add(new CommissionValue
                {
                    CompanyType = dicCompanyType[item.CompanyTypeId],
                    GameType = dicGameType[item.GameId],
                    CommissionId = item.CommissionId,
                    Comm = item.Comm
                });
            }

            DaCommValue.ExecuteWithTransaction(() =>
            {
                DaCommValue.DeleteCommission(commissionId);
                commssionValueList.ForEach(it => DaCommValue.InsertCommission(it));
            });
        }

        public UserCommission GetUserCommission(User user, LotterySpeciesEnum specie)
        {
            return DaUserComm.GetUserCommission(user, specie);
        }
        public UserCommission GetUserCommission(int commissionId)
        {
            return DaUserComm.GetUserCommission(commissionId);
        }
        public IList<CommissionValue> GetCommissionValue(int commissionId)
        {
            return DaCommValue.GetCommValues(commissionId);
        }
        /// <summary>
        /// 获取用户的佣金分组.
        /// </summary>
        /// <param name="userId">用户Id.</param>
        /// <param name="specieId">需要获取的佣金分组所属彩票种类.</param>
        /// <returns></returns>
        public IList<CommissionGroupModel> GetUserCommissionGroup(int userId, int specieId)
        {
            var parentUser = UserFacade.GetUserFamily(userId, true);
            var commissionGroup = CommGroupFacade.GetCommissionGroupBySpecie(specieId);
            List<CommissionItem> diffComm = new List<CommissionItem>();
            foreach (var user in parentUser)
            {
                var comms = user.UserCommission.FindAll(it => it.SpecieId == specieId);
                foreach (var comm in comms)
                {
                    var commValues = DaCommValue.GetCommValues(comm.CommissionId);
                    UserCommAddDiff(diffComm, commValues);
                }
            }
            UpdateUserCommGroup(commissionGroup, diffComm);
            return commissionGroup;
        }
        /// <summary>
        /// 获取用户(Company,Super,Master,Agent)的佣金信息.
        /// </summary>
        /// <param name="userId">用户Id.</param>
        /// <param name="member">Guest用户.</param>
        /// <param name="specieId">The specie id.</param>
        /// <returns></returns>
        public CommissionGroupModel GetUserCommission(User user, User member, int specieId)
        {
            if (user.Role >= SystemRole.Guest)
                throw new InvalidRoleException(SystemRole.Agent | SystemRole.Master | SystemRole.Super | SystemRole.Company, user.Role);
            if (user.Role == SystemRole.Company)
                return GetCompanyCommission(user, member, specieId);        //公司特殊处理
            var memberPack = DaMemberPack.GetMemberPackageBySpecie(member, specieId);       //获取用户所在分组
            if (memberPack == null)
                throw new InvalidDataException("memberpack is null;userId:" + member.UserId);
            var commGroupModel = CommGroupFacade.GetCommissionGroupModel(memberPack.GroupId);       //获取佣金分组信息
            var parentUser = UserFacade.GetUserFamily(user.UserId, true);
            List<CommissionItem> diffComm = new List<CommissionItem>();
            foreach (var parent in parentUser)
            {
                var comms = parent.UserCommission.FindAll(it => it.SpecieId == specieId);
                foreach (var comm in comms)
                {
                    var commValues = DaCommValue.GetCommValues(comm.CommissionId);
                    UserCommAddDiff(diffComm, commValues);      //添加佣金差
                }
            }
            UpdateUserCommGroup(commGroupModel, diffComm);
            return commGroupModel;
        }
        /// <summary>
        /// 获取用户所在分组的佣金表.
        /// </summary>
        /// <param name="member">用户.</param>
        /// <param name="specieId">彩票种类.</param>
        /// <returns></returns>
        public CommissionGroupModel GetMemberCommission(int memberId, int specieId)
        {
            var member = UserFacade.DaUser.GetUserById(memberId);
            if (member.Role != SystemRole.Guest)
                throw new InvalidRoleException(SystemRole.Guest, member.Role);
            var memberPack = DaMemberPack.GetMemberPackageBySpecie(member, specieId);       //获取用户所在分组
            if (memberPack == null)
                throw new InvalidDataException("memberpack is null;userId:" + memberId);
            var commGroupModel = CommGroupFacade.GetCommissionGroupModel(memberPack.GroupId);       //获取佣金分组信息
            var parentUser = UserFacade.GetUserFamily(member.UserId, true);                  //获取父级用户，并加载该用户的分成信息
            List<CommissionItem> diffComm = new List<CommissionItem>();
            foreach (var user in parentUser)
            {
                var comms = user.UserCommission.FindAll(it => it.SpecieId == specieId);
                foreach (var comm in comms)
                {
                    var commValues = DaCommValue.GetCommValues(comm.CommissionId);
                    UserCommAddDiff(diffComm, commValues);              //累加佣金差
                }
            }
            UpdateUserCommGroup(commGroupModel, diffComm);
            return commGroupModel;
        }
        /// <summary>
        /// 获取公司的佣金信息
        /// </summary>
        /// <param name="company">The company.</param>
        /// <param name="member">The member.</param>
        /// <param name="specieId">The specie id.</param>
        /// <returns></returns>
        private CommissionGroupModel GetCompanyCommission(User company, User member, int specieId)
        {
            var parentUser = UserFacade.GetParentUser(member);
            var super = parentUser.Find(it => it.Role == SystemRole.Super);
            var superCommModel = GetUserCommission(super, member, specieId);
            CommissionGroupModel commModel = new CommissionGroupModel
            {
                CommGroup = superCommModel.CommGroup,
                ConcreteCommissionList = new List<ConcreteCommission>()
            };
            foreach (var concreteComm in superCommModel.ConcreteCommissionList)
            {
                commModel.ConcreteCommissionList.Add(new ConcreteCommission
                {
                    Group = concreteComm.Group,
                    GameType = concreteComm.GameType,
                    CompanyType = concreteComm.CompanyType,
                    Commission = 100 - concreteComm.Commission,
                    Odds = concreteComm.Odds
                });
            }
            return commModel;
        }
        /// <summary>
        /// 添加用户佣金查
        /// </summary>
        /// <param name="diffCommList">总佣金差列表.</param>
        /// <param name="commValueList">用户佣金.</param>
        private void UserCommAddDiff(IList<CommissionItem> diffCommList, IList<CommissionValue> commValueList)
        {
            foreach (var commVal in commValueList)
            {
                var commItem = diffCommList.Find(it => it.CompanyTypeId == commVal.CompanyType.Id && it.GameTypeId == commVal.GameType.GameId);
                if (commItem == null)
                    diffCommList.Add(commItem = new CommissionItem { CompanyTypeId = commVal.CompanyType.Id, GameTypeId = commVal.GameType.GameId, Commission = 0, Odds = 0 });
                commItem.Commission += commVal.Comm;
                commItem.Odds += commVal.Odds;
            }
        }
        private void UpdateUserCommGroup(IList<CommissionGroupModel> models, List<CommissionItem> diffComm)
        {
            foreach (var model in models)
            {
                UpdateUserCommGroup(model, diffComm);
            }
        }
        /// <summary>
        /// 更新用户佣金分组佣金差.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="diffComm">具体佣金差.</param>
        private void UpdateUserCommGroup(CommissionGroupModel model, List<CommissionItem> diffComm)
        {
            if (diffComm.Count == 0) return;
            foreach (var concreteComm in model.ConcreteCommissionList)
            {
                var diffCommItem = diffComm.Find(it => it.CompanyTypeId == concreteComm.CompanyType.Id && it.GameTypeId == concreteComm.GameType.GameId);
                if (diffCommItem == null) continue;
                concreteComm.Commission -= diffCommItem.Commission;
            }
        }
    }
}
